﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using chess;
using System.Threading;


namespace ChessApp
{
    public sealed partial class MainPage : Page
    {

        private Canvas[,] _board = new Canvas[8,8];
        private Color _fieldBackgroundDark = Colors.SandyBrown;
        private Color _fieldBackgroundLight = Colors.Wheat;
        private Color _fieldMarked = Colors.Yellow;
        private Color _fieldMarkedAndOffended = Colors.Red;
        private csChess _chess = new csChess();
        private csField _moveStartField = null;
        private int _defaultFieldWith = 20;
        private int _fieldWidth = 20;

        enumFigParty _currentlyMoving = enumFigParty.White;

        public MainPage()
        {
            this.InitializeComponent();
        }

        private void MainFrame_App_Loaded(object sender, RoutedEventArgs e)
        {
            double topPanelHeight = TopPanel.ActualHeight;
            double newFieldWidth = this._defaultFieldWith;
            newFieldWidth = this._defaultFieldWith / 200.0 * topPanelHeight;

            this._fieldWidth = Convert.ToInt32(Math.Round(newFieldWidth));
            canvas_board.Width = this._fieldWidth * 10;
            canvas_board.Height = this._fieldWidth * 10;

            this._chess.Initialize();
            this._chess.OnKingDead += _chess_OnKingDead;
            this._chess.OnStandOff += _chess_OnStandOff;
            this._chess.OnGoingToMakeMove += _chess_OnGoingToMakeMove;
            this._chess.OnMoveMade += _chess_OnMoveMade;
            //this.PlaceFigures();            
            this.InitializeBoard();

            DispatcherTimer dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Tick += DispatcherTimer_Tick;
            dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
            dispatcherTimer.Start();
        }

        private void DispatcherTimer_Tick(object sender, object e)
        {
            if (this.radioButton_gamemode_computerVScomputer.IsChecked == true)
            {
                this.DoAutomaticGameplay();
            }

            if (this.radioButton_gamemode_humanVScomputer.IsChecked == true)
            {
                this.DoPlayAgainstComputer();
            }
        }

        private void DoPlayAgainstComputer()
        {
            if (this._currentlyMoving == enumFigParty.Black)
            {
                this._chess.ExecuteMove(enumFigParty.Black, enumFieldMarkerType.destination);
                this._currentlyMoving = this.changeMovingParty(this._currentlyMoving);
            }
        }
        
        private void DoAutomaticGameplay()
        {
            switch (this._currentlyMoving)
            {
                case enumFigParty.White:
                    this._chess.ExecuteMove(enumFigParty.White, enumFieldMarkerType.destination);
                    break;
                case enumFigParty.Black:
                    this._chess.ExecuteMove(enumFigParty.Black, enumFieldMarkerType.destination);
                    break;
                default:
                    break;
            }
            this._currentlyMoving = this.changeMovingParty(this._currentlyMoving);
        }

        private void _chess_OnMoveMade()
        {
            this.PlaceFigures();
        }

        private void _chess_OnGoingToMakeMove(object sender, string move)
        {
            //throw new NotImplementedException();
        }

        private void ResetBoard()
        {
            this._chess.Initialize();
            this.PlaceFigures();
        }

        private void _chess_OnStandOff()
        {
            this.ResetBoard();
        }

        private void _chess_OnKingDead(enumFigParty party)
        {
            switch (party)
            {
                case enumFigParty.White:
                    break;
                case enumFigParty.Black:
                    break;
                default:
                    return;
            }
            this.ResetBoard();
        }

        private void InitializeBoard()
        {
            TextBlock tb = null;

            for (int i = 0; i < 8; i++)
            {
                Canvas borderTop = new Canvas();
                borderTop.Width = this._fieldWidth;
                borderTop.Height = this._fieldWidth;
                Canvas.SetLeft(borderTop, (i + 1) * this._fieldWidth);
                Canvas.SetTop(borderTop, 0);
                borderTop.Background = new SolidColorBrush(Colors.Brown);
                canvas_board.Children.Add(borderTop);
                tb = new TextBlock();
                tb.Width = this._fieldWidth;
                tb.Height = this._fieldWidth;
                tb.Text = Tools.columnTranslation[i];
                tb.Foreground = new SolidColorBrush(Colors.White);
                tb.TextAlignment = TextAlignment.Center;
                borderTop.Children.Add(tb);

                Canvas borderBottom = new Canvas();
                borderBottom.Width = this._fieldWidth;
                borderBottom.Height = this._fieldWidth;
                Canvas.SetLeft(borderBottom, (i + 1) * this._fieldWidth);
                Canvas.SetTop(borderBottom, this._fieldWidth * 9);
                borderBottom.Background = new SolidColorBrush(Colors.Brown);
                canvas_board.Children.Add(borderBottom);
                tb = new TextBlock();
                tb.Width = this._fieldWidth;
                tb.Height = this._fieldWidth;
                tb.Text = Tools.columnTranslation[i];
                tb.Foreground = new SolidColorBrush(Colors.White);
                tb.TextAlignment = TextAlignment.Center;
                borderBottom.Children.Add(tb);

                Canvas borderLeft = new Canvas();
                borderLeft.Width = this._fieldWidth;
                borderLeft.Height = this._fieldWidth;
                Canvas.SetLeft(borderLeft, 0);
                Canvas.SetTop(borderLeft, (i + 1) * this._fieldWidth);
                borderLeft.Background = new SolidColorBrush(Colors.Brown);
                canvas_board.Children.Add(borderLeft);
                tb = new TextBlock();
                tb.Width = this._fieldWidth;
                tb.Height = this._fieldWidth;
                tb.Text = Convert.ToString(8 - i);
                tb.Foreground = new SolidColorBrush(Colors.White);
                tb.TextAlignment = TextAlignment.Center;
                borderLeft.Children.Add(tb);

                Canvas borderRight = new Canvas();
                borderRight.Width = this._fieldWidth;
                borderRight.Height = this._fieldWidth;
                Canvas.SetLeft(borderRight, this._fieldWidth * 9);
                Canvas.SetTop(borderRight, (i + 1) * this._fieldWidth);
                borderRight.Background = new SolidColorBrush(Colors.Brown);
                canvas_board.Children.Add(borderRight);
                tb = new TextBlock();
                tb.Width = this._fieldWidth;
                tb.Height = this._fieldWidth;
                tb.Text = Convert.ToString(8 - i);
                tb.Foreground = new SolidColorBrush(Colors.White);
                tb.TextAlignment = TextAlignment.Center;
                borderRight.Children.Add(tb);


                for (int j = 0; j < 8; j++)
                {
                    this._board[i, j] = new Canvas();
                    this._board[i, j].Width = this._fieldWidth;
                    this._board[i, j].Height = this._fieldWidth;
                    this._board[i, j].Tapped += this.BoardTapped; ;
                    Canvas.SetLeft(this._board[i, j], (i + 1) * this._fieldWidth);
                    Canvas.SetTop(_board[i, j], (j + 1) * this._fieldWidth);

                    csField field = _chess.GetField(i, j);

                    csFig fig = field.GetFig;
                    if (fig != null)
                    {
                        tb = new TextBlock();
                        tb.Width = this._fieldWidth;
                        tb.Height = this._fieldWidth;
                        tb.Text = fig.FigType.ToString();
                        tb.DoubleTapped += this.BoardDoubleTapped;

                        if (fig.Marked == true)
                        {
                            tb.Foreground = new SolidColorBrush(Colors.Red);
                        }
                        else
                        {
                            if (fig.Party == enumFigParty.Black)
                            {
                                tb.Foreground = new SolidColorBrush(Colors.Black);
                            }
                            else
                            {
                                tb.Foreground = new SolidColorBrush(Colors.White);
                            }
                        }
                        tb.TextAlignment = TextAlignment.Center;
                        this._board[i, j].Children.Add(tb);
                    }

                    if (this._chess.GetField(i, j).Marked)
                    {
                        _board[i, j].Background = new SolidColorBrush(this._fieldMarked);
                    }
                    else
                    {
                        if (j % 2 == 0)
                        {
                            if (i % 2 == 0)
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundLight);
                            }
                            else
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundDark);
                            }
                        }
                        else
                        {
                            if (i % 2 == 0)
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundDark);
                            }
                            else
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundLight);
                            }
                        }
                    }
                    canvas_board.Children.Add(_board[i, j]);
                }
            }
        }


        // Platziert die Figuren auf dem Schachbrett gemäß der Aufstellung in der Chess-DLL
        private void PlaceFigures()
        {
            TextBlock tb = null;

            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    csField field = _chess.GetField(i, j);
                    csFig fig = field.GetFig;
                    if (fig != null)
                    {
                        tb = (TextBlock)this._board[i, j].Children[0];
                        bool textBlockCreated = false;
                        if (tb == null)
                        {
                            tb = new TextBlock();
                            tb.Width = this._fieldWidth;
                            tb.Height = this._fieldWidth;
                            tb.Text = fig.FigType.ToString();
                            tb.DoubleTapped += this.BoardDoubleTapped;
                            this._board[i, j].Children.Add(tb);
                            textBlockCreated = true;
                        }
                        tb.Width = this._fieldWidth;
                        tb.Height = this._fieldWidth;
                        tb.Text = fig.FigType.ToString();

                        if (fig.Marked == true)
                        {
                            tb.Foreground = new SolidColorBrush(Colors.Red);
                        }
                        else
                        {
                            if (fig.Party == enumFigParty.Black)
                            {
                                tb.Foreground = new SolidColorBrush(Colors.Black);
                            }
                            else
                            {
                                tb.Foreground = new SolidColorBrush(Colors.Wheat);
                            }
                        }
                        tb.TextAlignment = TextAlignment.Center;

                        // Wurde der Textblock neu angelegt, dann ist die Figur auf dieser
                        // Position neu. Daher muss der TextBlock als Child zum canvas des Feldes hinzugefügt werden
                        if (textBlockCreated)
                        {
                            //this._board[i, j].Children.Add(tb);
                        }
                    } else
                    {
                        // Ist die Figur NULL, also das Feld leer, exisitert aber trotzdem ein TextBlock,
                        // muss dieser aus der Childrenliste des Feld-Canvas entfernt werden.
                        if (this._board[i, j].Children.Count > 0)
                        {
                            this._board[i, j].Children.RemoveAt(0);
                        }
                    }

                    if (this._chess.GetField(i, j).Marked)
                    {
                        if (this._chess.GetField(i, j).Offended)
                        {
                            _board[i, j].Background = new SolidColorBrush(this._fieldMarkedAndOffended);
                        }
                        else
                        {
                            _board[i, j].Background = new SolidColorBrush(this._fieldMarked);
                        }
                    }
                    else
                    {
                        if (j % 2 == 0)
                        {
                            if (i % 2 == 0)
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundLight);
                            }
                            else
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundDark);
                            }
                        }
                        else
                        {
                            if (i % 2 == 0)
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundDark);
                            }
                            else
                            {
                                _board[i, j].Background = new SolidColorBrush(this._fieldBackgroundLight);
                            }
                        }
                    }
                    //canvas_board.Children.Add(_board[i, j]);
                }
            }
        }

        private void BoardDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
        {
            if (sender is TextBlock)
            {
                this._chess.UnmarkAllFields();
                this._chess.UnmarkAllFigures();

                int left = (int)Canvas.GetLeft(((Canvas)((TextBlock)sender).Parent)) / this._fieldWidth - 1;
                int top = (int)Canvas.GetTop(((Canvas)((TextBlock)sender).Parent)) / this._fieldWidth - 1;

                csField field = this._chess.GetField(left, top);
                csFig figure = field.GetFig;

                if ((figure != null)&&(figure.Party == this._currentlyMoving))
                {
                    // Markiere angreifbare Felder
                    switch (figure.Party)
                    {
                        case enumFigParty.White:
                            this._chess.MarkFields(enumFigParty.Black, enumFieldMarkerType.offended);
                            break;
                        case enumFigParty.Black:
                            this._chess.MarkFields(enumFigParty.White, enumFieldMarkerType.offended);
                            break;
                        default:
                            this._chess.MarkFields(enumFigParty.White, enumFieldMarkerType.none);
                            break;
                    }

                    this._chess.MarkFields(field, enumFieldMarkerType.destination);
                    figure.Marked = true;
                    this._moveStartField = field;
                }
                this.PlaceFigures();
            }
        }

        private enumFigParty changeMovingParty(enumFigParty currentlyMoving)
        {
            if (currentlyMoving == enumFigParty.White)
            {
                return enumFigParty.Black;
            }
            else
            {
                return enumFigParty.White;
            }
        }

        // Wird ausgelöst, wenn einmal auf das Zielfeld getippt wird
        private void BoardTapped(object sender, TappedRoutedEventArgs e)
        {
            Canvas canvasField = null;
            bool moveExecuted = false;

            // Ist kein Feld für den Start eines Zuges gewählt worden
            if (_moveStartField == null)
            {
                // dann raus ->
                return;
            }

            if (sender is TextBlock)
            {
                // Es wurde ein Textblock angeklickt, das heißt, es befindet sich eine Figur auf dem Zielfeld
                TextBlock tb = (TextBlock)sender;
                canvasField = (Canvas)tb.Parent;
            }

            if (sender is Canvas)
            {
                // Ist der Sender ein Canvas.Objekt, ist das Feld leer
                canvasField = (Canvas)sender;
            }

            // Die Koordinaten werden anhand der Koordinaten des Feld-Canvas im Board.Canvas ermittelt
            int left = (int)Canvas.GetLeft(canvasField) / this._fieldWidth - 1;
            int top = (int)Canvas.GetTop(canvasField) / this._fieldWidth - 1;

            // Daraus werden die Koordinaten des Feld-Objekts im Board-Array errechnet
            csField field = this._chess.GetField(left, top);
            csFig figure = field.GetFig;

            // Ist bereits eines gewählt, dann ermittle Figur auf dem Feld
            csFig figureToMove = _moveStartField.GetFig;
            if (figureToMove != null)
            {
                // Ist das Zeielfeld leer?
                if (figure == null)
                {
                    // Ja, Zielfeld ist leer, führe Zug aus
                    moveExecuted = this._chess.ManualMove(figureToMove.Party, field, enumFieldMarkerType.destination);
                    if (moveExecuted)
                    {
                        this._currentlyMoving = this.changeMovingParty(this._currentlyMoving);
                    }
                    return;
                }
                else
                {
                    // Nein, dort steht eine Figur. Hat diese eine andere Farbe als die ziehende Figur?
                    if (figureToMove.Party != figure.Party)
                    {
                        // Ja, Figur auf dem Zielfeld hat eine andere Farbe => Führe Zug aus und schlage gegnerische Figur
                        moveExecuted = this._chess.ManualMove(figureToMove.Party, field, enumFieldMarkerType.destination);
                        if (moveExecuted)
                        {
                            this._currentlyMoving = this.changeMovingParty(this._currentlyMoving);
                        }
                        return;
                    }
                    else
                    {
                        // Nein, Figur auf dem Zielfeld hat die gleiche Farbe, wie die selektierte Figur
                        // deselektiere die alte Figur
                        this._chess.UnmarkAllFigures();
                        // -> selektiere die neue Figur
                        figure.Marked = true;
                    }
                }
            }
        }

        private void button_restart_Click(object sender, RoutedEventArgs e)
        {
            this._chess.Initialize();
            this.PlaceFigures();
            this._currentlyMoving = enumFigParty.White;
        }

        private void button_makeMove_white_Click(object sender, RoutedEventArgs e)
        {
            if (this._chess != null)
            {
                if (this._currentlyMoving == enumFigParty.White)
                {
                    this._chess.ExecuteMove(enumFigParty.White, enumFieldMarkerType.destination);
                    this._currentlyMoving = this.changeMovingParty(this._currentlyMoving);
                }
            }
        }

        private void button_makeMove_black_Click(object sender, RoutedEventArgs e)
        {
            if (this._chess != null)
            {
                if (this._currentlyMoving == enumFigParty.Black)
                {
                    this._chess.ExecuteMove(enumFigParty.Black, enumFieldMarkerType.destination);
                    this._currentlyMoving = this.changeMovingParty(this._currentlyMoving);
                }
            }
        }

        private void button_automatic_move(object sender, RoutedEventArgs e)
        {
            if (this._currentlyMoving == enumFigParty.White)
            {
                this._chess.ExecuteMove(enumFigParty.White, enumFieldMarkerType.destination);
            } else
            {
                this._chess.ExecuteMove(enumFigParty.Black, enumFieldMarkerType.destination);
            }
            this._currentlyMoving = this.changeMovingParty(this._currentlyMoving);
        }

        private void buttonQuit_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Exit();                     
        }
    }
}
